﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace CodePlex.Resourceful.Amazon.SQS
{
    public class SQSClient : QueryAPIClient
    {

        public static readonly string DefaultServiceHost = "queue.amazonaws.com";
        private static readonly string Version = "2009-02-01";

        public SQSClient(string accessKeyID, string secretAccessKey, bool useSSL, string method)
            : base(accessKeyID, secretAccessKey, useSSL, method, DefaultServiceHost, Version) { }





        // list queues
        public ClientResponse ListQueues(string queueNamePrefix)
        {

            // queueNamePrefix Constraints: Maximum 80 characters; alphanumeric characters, hyphens (-), and underscores (_) are allowed.

            string path = "";

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "ListQueues";

            if (!string.IsNullOrEmpty(queueNamePrefix))
                parameters["QueueNamePrefix"] = queueNamePrefix;

            return DoQueryRequest( path, parameters);


            /* actual response
            200 OK
            Transfer-Encoding:chunked
            Content-Type:text/xml
            Date:Sun, 21 Jun 2009 23:25:42 GMT
            Server:AWS Simple Queue Service
            <?xml version="1.0"?>
            <ListQueuesResponse xmlns="http://queue.amazonaws.com/doc/2009-02-01/">
              <ListQueuesResult></ListQueuesResult>
              <ResponseMetadata>
                <RequestId>2f370f01-bbdd-4014-ba58-0af755bb1f4c</RequestId>
              </ResponseMetadata>
            </ListQueuesResponse>

            */


            //http://queue.amazonaws.com/
            //?Action=ListQueues
            //&QueueNamePrefix=t
            //&Version=2009-02-01
            //&SignatureMethod=HmacSHA256
            //&Expires=2009-04-18T22%3A52%3A43PST
            //&AWSAccessKeyId=0GS7553JW74RRM612K02EXAMPLE
            //&SignatureVersion=2
            //&Signature=Dqlp3Sd6ljTUA9Uf6SGtEExwUQEXAMPLE

            //<ListQueuesResponse>
            //    <ListQueuesResult>
            //        <QueueUrl>
            //            http://queue.amazonaws.com/123456789012/testQueue
            //        </QueueUrl>
            //    </ListQueuesResult>
            //    <ResponseMetadata>
            //        <RequestId>
            //            725275ae-0b9b-4762-b238-436d7c65a1ac
            //        </RequestId>
            //    </ResponseMetadata>
            //</ListQueuesResponse>


        }


        // create queue
        public ClientResponse CreateQueue(string queueName, TimeSpan? defaultVisibilityTimeout)
        {
            // queueName (r): Constraints: Maximum 80 characters; alphanumeric characters, hyphens (-), and underscores (_) are allowed.
            // defaultVisibilityTimeout: The visibility timeout (in seconds) to use for this queue. Type: Integer Constraints: 0 to 43200 (maximum 12 hours) Default: 30 seconds

            int? dvt = null;
            if (defaultVisibilityTimeout.HasValue)
                dvt = (int)defaultVisibilityTimeout.Value.TotalSeconds;


            string path = "";

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "CreateQueue";

            if (!string.IsNullOrEmpty(queueName))
                parameters["QueueName"] = queueName;

            if (dvt.HasValue)
                parameters["DefaultVisibilityTimeout"] = dvt.Value.ToString();

            return DoQueryRequest( path, parameters);
        }




        // delete queue
        public ClientResponse DeleteQueue(string queueUrl)
        {

            string path = NormalizeQueueUrl(queueUrl);

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "DeleteQueue";

            return DoQueryRequest(path, parameters);
        }



        // get queue attributes
        public ClientResponse GetQueueAttributes(string queueUrl, QueueAttributes attributes)
        {

            string path = NormalizeQueueUrl(queueUrl);

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "GetQueueAttributes";

            List<QueueAttributes> attributeList = new List<QueueAttributes>();

            if ((attributes & QueueAttributes.All) == QueueAttributes.All)
            {
                attributeList.Add(QueueAttributes.All);
            }
            else
            {
                if ((attributes & QueueAttributes.ApproximateNumberOfMessages) == QueueAttributes.ApproximateNumberOfMessages)
                    attributeList.Add(QueueAttributes.ApproximateNumberOfMessages);
                if ((attributes & QueueAttributes.ApproximateNumberOfMessagesNotVisible) == QueueAttributes.ApproximateNumberOfMessagesNotVisible)
                    attributeList.Add(QueueAttributes.ApproximateNumberOfMessagesNotVisible);
                if ((attributes & QueueAttributes.VisibilityTimeout) == QueueAttributes.VisibilityTimeout)
                    attributeList.Add(QueueAttributes.VisibilityTimeout);
                if ((attributes & QueueAttributes.CreatedTimestamp) == QueueAttributes.CreatedTimestamp)
                    attributeList.Add(QueueAttributes.CreatedTimestamp);
                if ((attributes & QueueAttributes.LastModifiedTimestamp) == QueueAttributes.LastModifiedTimestamp)
                    attributeList.Add(QueueAttributes.LastModifiedTimestamp);
                if ((attributes & QueueAttributes.Policy) == QueueAttributes.Policy)
                    attributeList.Add(QueueAttributes.Policy);
            }

            AddAttributes(parameters, attributeList);

            return DoQueryRequest(path, parameters);
        }


      

        // send message
        public ClientResponse SendMessage(string queueUrl, string messageBody)
        {
            // String maximum 8 KB in size
            //The following list shows the characters (in Unicode) allowed in your message, according to the W3C XML specification (for more information, go to http://www.w3.org/TR/REC-xml/#charsets). If you send any characters not included in the list, your request will be rejected.
            //#x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to #x10FFFF]
            
                
            string path = NormalizeQueueUrl(queueUrl);

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "SendMessage";
            parameters["MessageBody"] = messageBody;

            return DoQueryRequest(path, parameters);
        }




        // receive message
        public ClientResponse ReceiveMessage(string queueUrl, int? maxNumberOfMessages, TimeSpan? visibilityTimeout, SendMessageAttributes? attributes)
        {


// MaxNumberOfMessages  : Maximum number of messages to return. SQS never returns more messages than this value but might return fewer.
//Not necessarily all the messages in the queue are returned (for more information, see the preceding note about machine sampling).
//Type: Integer from 1 to 10
//Default: 1

//VisibilityTimeout: The duration (in seconds) that the received messages are hidden from subsequent retrieve requests after being retrieved by a ReceiveMessage request.
//Type: Integer
//Constraints: 0 to 43200 (maximum 12 hours)
//Default: The visibility timeout for the queue

            int? visTimeout = null;
            if (visibilityTimeout.HasValue)
                visTimeout = (int)visibilityTimeout.Value.TotalSeconds;


            string path = NormalizeQueueUrl(queueUrl);

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "ReceiveMessage";

            if (maxNumberOfMessages.HasValue)
                parameters["MaxNumberOfMessages"] = maxNumberOfMessages.Value.ToString();
            if (visTimeout.HasValue)
                parameters["VisibilityTimeout"] = visTimeout.Value.ToString();

            if (attributes.HasValue)
            {
                List<SendMessageAttributes> attributeList = new List<SendMessageAttributes>();
                if ((attributes & SendMessageAttributes.All) == SendMessageAttributes.All)
                {
                    attributeList.Add(SendMessageAttributes.All);
                }
                else
                {
                    if ((attributes.Value & SendMessageAttributes.SenderId) == SendMessageAttributes.SenderId)
                        attributeList.Add(SendMessageAttributes.SenderId);
                    if ((attributes.Value & SendMessageAttributes.SentTimestamp) == SendMessageAttributes.SentTimestamp)
                        attributeList.Add(SendMessageAttributes.SentTimestamp);
                    if ((attributes.Value & SendMessageAttributes.ApproximateReceiveCount) == SendMessageAttributes.ApproximateReceiveCount)
                        attributeList.Add(SendMessageAttributes.ApproximateReceiveCount);
                    if ((attributes.Value & SendMessageAttributes.ApproximateFirstReceiveTimestamp) == SendMessageAttributes.ApproximateFirstReceiveTimestamp)
                        attributeList.Add(SendMessageAttributes.ApproximateFirstReceiveTimestamp);

                }
                AddAttributes(parameters, attributeList);
            }


            return DoQueryRequest(path, parameters);
        }



//<SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2009-02-01/">
//  <SendMessageResult>
//    <MD5OfMessageBody>fc5e038d38a57032085441e7fe7010b0</MD5OfMessageBody>
//    <MessageId>262d56c0-c95f-4d58-8427-f028b17d1642</MessageId>
//  </SendMessageResult>
//  <ResponseMetadata>
//    <RequestId>2957a9a6-0183-4ec5-8845-d932e3e3e181</RequestId>
//  </ResponseMetadata>
//</SendMessageResponse>




//<ReceiveMessageResponse xmlns="http://queue.amazonaws.com/doc/2009-02-01/">
//  <ReceiveMessageResult>
//    <Message>
//     <MessageId>262d56c0-c95f-4d58-8427-f028b17d1642</MessageId>
//     <ReceiptHandle>+eXJYhj5rDpT/JkQ9kX4ioaqYBhkvMoiO3S/rQl54+90DJ3gVOmjI2Gh/oFnb0IeJqy5Zc8kH4Lqk6zX7Exf+zaAPSeOkXQZyMbJXeX7DkmClRW1r64iV25wv0xoRbJ39a5150C1KnHyV9sUPidF0c9QKqwm9541qS7Mn6V3qh8=</ReceiptHandle>
//     <MD5OfBody>fc5e038d38a57032085441e7fe7010b0</MD5OfBody>
//     <Body>helloworld</Body>
//    </Message>
//  </ReceiveMessageResult>
//  <ResponseMetadata>
//    <RequestId>50467281-9018-4b67-a88e-0ffdb08fe77d</RequestId>
//  </ResponseMetadata>
//</ReceiveMessageResponse>


        // ChangeMessageVisibility
        public ClientResponse ChangeMessageVisibility(string queueUrl, string receiptHandle, TimeSpan visibilityTimeout)
        {
            int visTimeout = (int)visibilityTimeout.TotalSeconds;
            
//visibilityTimeout: The new value for the message's visibility timeout (in seconds).
//Type: Integer from 0 to 43200 (maximum 12 hours)
//Constraints: This value is limited to 43200 seconds (12 hours)

            
            string path = NormalizeQueueUrl(queueUrl);

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "ChangeMessageVisibility";

            parameters["ReceiptHandle"] = receiptHandle;
            parameters["VisibilityTimeout"] = visTimeout.ToString();

            return DoQueryRequest(path, parameters);


        }






        // DeleteMessage
        public ClientResponse DeleteMessage(string queueUrl, string receiptHandle)
        {
           
            string path = NormalizeQueueUrl(queueUrl);

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "DeleteMessage";

            parameters["ReceiptHandle"] = receiptHandle;
            
            return DoQueryRequest(path, parameters);


        }





        // TODO AddPermission
        // TODO RemovePermission
        // TODO SetQueueAttributes

















        private void AddAttributes<TAttribute>(NameValuePairs parameters, IEnumerable<TAttribute> attributes)
        {
            int i = 1;
            foreach (TAttribute att in attributes)
            {
                parameters["AttributeName." + i++] = att.ToString();
            }
        }



        private string NormalizeQueueUrl(string url)
        {
            Uri uri = new Uri(url);
            return uri.PathAndQuery;
        }

        

     
    }
}
